home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / internet / other / ka9q / ka9q_src.arc / SLFP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1988-12-02  |  12.0 KB  |  523 lines

  1. /* Send and receive IP datagrams on serial lines. Compatible with SL/FP
  2.  * as used with the Merit Network and MIT.
  3.  */
  4. #include <stdio.h>
  5. #include "global.h"
  6. #include "mbuf.h"
  7. #include "iface.h"
  8. #include "timer.h"
  9. #include "ip.h"
  10. #include "slfp.h"
  11. #ifdef UNIX    /* BSD or SYS5 */
  12. #include "unix.h"
  13. #else
  14. # ifdef ATARI_ST
  15. #  include "st.h"
  16. # else
  17. #  include "pc.h"
  18. #  include "asy.h"
  19. # endif        /* ATARI_ST */
  20. #endif        /* BSD or SYS5 */
  21. #include "trace.h"
  22.  
  23. int asy_ioctl();
  24. int slfp_send();
  25. int doslfp();
  26. int asy_output();
  27.  
  28. /* SL/FP level control structure */
  29. struct slfp slfp[ASY_MAX];
  30. char slfp_ack[ACK_LEN] = { SLFP_ACK } ;
  31. char slfp_req[REQ_LEN] = { SLFP_REQ } ;
  32. char ip_hdr[HDR_LEN] = { 2, 1, 0, 0 } ;    /* IP Packet Header */
  33. char ar_hdr[HDR_LEN] = { 2, 3, 0, 0 } ;    /* "Addr Req" Packet Header */
  34. struct interface asy_interface =    /* Fake interface for "dump" proc */
  35.     { NULLIF, "asy" } ;        /* Name of "asy" interface */
  36.  
  37. /* Routine to Initialize the Async line for SL/FP processing.
  38.  * Mostly involves requesting the IP Address for this host.
  39.  */
  40. int
  41. slfp_init(interface,pip_addr,modem_cmd)
  42. struct interface *interface ;
  43. int32 *pip_addr ;        /* pointer to host ip address */
  44. char *modem_cmd ;        /* optional command to Modem */
  45. {
  46.     register struct slfp *sp;
  47.     register struct timer *ar ;
  48.     char *modem_line ;
  49.     int i ;
  50.  
  51.     sp = &slfp[interface->dev];
  52.     ar = &sp->ar_timer ;
  53.     sp->ar_pending = 1 ;
  54.     slfp[interface->dev].req_pending = 0 ;
  55.  
  56.     /* If a Modem Command is present, send it and wait for Connection */
  57.     if (modem_cmd != NULLCHAR) {
  58.     char c; c='\r';
  59.     modem_line = (char *)malloc(strlen(modem_cmd)+2) ;
  60.     if (modem_line == NULLCHAR)
  61.         return -1 ;
  62.     strcpy(modem_line, modem_cmd);
  63.     strcat(modem_line, "\r") ;
  64.     asy_output(interface->dev,&c,1);    /* Wake up modem */
  65.     set_timer(ar,500);
  66.     start_timer(ar);
  67.     while(ar->state == TIMER_RUN)
  68.         keep_things_going();
  69.     asy_output(interface->dev,modem_line,strlen(modem_line));
  70.     set_timer(ar, 30000) ;    /* Wait upto 30 seconds for Connection */
  71.     } else
  72.     set_timer(ar, 500) ; /* Wait half a second before sending REQ's */
  73.  
  74.     /* Request an IP Address upto 4 times (every 24 seconds) before giving up */
  75.     for (i=0; i<4; i++) {
  76.     start_timer(ar) ;
  77.     while (sp->ar_pending && (ar->state == TIMER_RUN)) {
  78.         keep_things_going() ;    /* Can't return until timeout or addr */
  79.         if(kbread()==(-2))        /* Hit the Escape key */
  80.         return(-1);
  81.     }
  82.     if (!sp->ar_pending) {
  83.         if (modem_cmd != NULLCHAR)
  84.         free(modem_line) ;
  85.         return 0 ;
  86.     }
  87.     slfp_send(NULLBUF, interface, 0L, 0, 0, 0, 0) ;
  88.     set_timer(ar, 24000) ;    /* Wait upto 24 seconds for IP Addr */
  89.     }
  90.  
  91.     if (modem_cmd != NULLCHAR)
  92.     free(modem_line) ;
  93.     sp->ar_pending = 0 ;
  94.     return -1 ;
  95. }
  96.  
  97. /* Send routine for point-to-point slfp
  98.  * This is a trivial function since slfp_encode adds the link-level header
  99.  */
  100. int
  101. slfp_send(bp,interface,gateway,precedence,delay,throughput,reliability)
  102. struct mbuf *bp;        /* Buffer to send */
  103. struct interface *interface;    /* Pointer to interface control block */
  104. int32 gateway;
  105. char precedence;
  106. char delay;
  107. char throughput;
  108. char reliability;
  109. {
  110.     if(interface == NULLIF){
  111.         free_p(bp);
  112.         return;
  113.     }
  114.     dump(interface,IF_TRACE_OUT,TRACE_IP,bp);
  115.     (*interface->raw)(interface,bp);
  116. }
  117. /* Send a raw slfp frame -- also trivial */
  118. slfp_raw(interface,bp)
  119. struct interface *interface;
  120. struct mbuf *bp;
  121. {
  122.     /* Make "asy" interface a shadow of the SLFP interface */
  123.     asy_interface.trace = interface->trace ;
  124.  
  125.     /* Queue a frame on the slfp output queue and start transmitter */
  126.     slfpq(interface->dev,bp);
  127. }
  128. /* Encode a raw packet in slfp framing, put on link output queue, and kick
  129.  * transmitter
  130.  */
  131. static
  132. slfpq(dev,bp)
  133. int16 dev;        /* Serial line number */
  134. struct mbuf *bp;    /* Buffer to be sent */
  135. {
  136.     register struct slfp *sp;
  137.     struct mbuf *slfp_encode();
  138.  
  139.     if((bp = slfp_encode(dev,bp)) == NULLBUF)
  140.         return;    
  141.  
  142.     sp = &slfp[dev];
  143.     enqueue(&sp->sndq,bp);
  144.     dump(&asy_interface,IF_TRACE_OUT,TRACE_SLFP,bp);
  145.     sp->sndcnt++;
  146.     if(sp->tbp == NULLBUF)
  147.         slfp_asy_start(dev);
  148. }
  149.  
  150. /* Handle REQ-ACK Timer expiration
  151.  */
  152. void
  153. slfp_req_notify(dev)
  154. int16 dev;
  155. {
  156.     register struct slfp *sp;
  157.     register struct timer *rt ;        /* Timer for REQ-ACK negotiation */
  158.     struct mbuf *bp ;
  159.  
  160.     sp = &slfp[dev];
  161.     rt = &(sp->req_timer) ;
  162.     if (sp->reqcnt++ >= 10) {
  163.     sp->tbp = NULLBUF ;
  164.     sp->req_pending = 0 ;
  165.     bp = dequeue(&sp->sndq);
  166.     sp->sndcnt--;
  167.     free_p(bp) ;
  168.     }
  169.     else {
  170.     set_timer(rt,2000) ;        /* 2-Second Timeout for ACK */
  171.     start_timer(rt) ;
  172.     asy_output(dev, slfp_req, REQ_LEN) ;
  173.     }
  174. }
  175.  
  176. /* Start output, if possible, on asynch device dev */
  177. static
  178. slfp_asy_start(dev)
  179. int16 dev;
  180. {
  181.     register struct slfp *sp;
  182.     register struct timer *rt ;    /* Timer for REQ-ACK negotiation */
  183.     struct mbuf *bp ;
  184.  
  185.     if(!stxrdy(dev))
  186.         return;        /* Transmitter not ready */
  187.  
  188.     sp = &slfp[dev];
  189.     bp = sp->tbp ;
  190.     if(bp != NULLBUF){
  191.         /* transmission just completed */
  192.         free_p(bp) ;
  193.         sp->tbp = NULLBUF;
  194.     }
  195.     if(sp->sndq == NULLBUF)
  196.         return;    /* No work */
  197.  
  198.     rt = &(sp->req_timer) ;
  199.     if (sp->req_pending)
  200.         return ;
  201.     sp->reqcnt = 0 ;
  202.     sp->req_pending = 1 ;
  203.     rt->func = slfp_req_notify ;
  204.     rt->arg = (char *)dev ;
  205.     set_timer(rt,2000) ;        /* 2-Second Timeout for ACK */
  206.     start_timer(rt) ;
  207.     asy_output(dev, slfp_req, REQ_LEN) ;
  208. }
  209. /* Encode a packet in SL/FP format */
  210. static
  211. struct mbuf *
  212. slfp_encode(dev,bp)
  213. int16 dev;        /* Serial line number */
  214. struct mbuf *bp;
  215. {
  216.     struct mbuf *lbp;    /* Mbuf containing line-ready packet */
  217.     register char *cp;
  218.     char c;
  219.  
  220.     /* Allocate output mbuf that's twice as long as the packet.
  221.      * This is a worst-case guess (consider a packet full of SLFP_ENDs!)
  222.      */
  223.     lbp = alloc_mbuf(HDR_LEN + 2*len_mbuf(bp) + 2);
  224.     if(lbp == NULLBUF){
  225.         /* No space; drop */
  226.         free_p(bp);
  227.         return NULLBUF;
  228.     }
  229.     cp = lbp->data;
  230.  
  231.     /* Prefix packet with the Correct Link-Level Header */
  232.     if (slfp[dev].ar_pending)
  233.         memcpy(cp, ar_hdr, HDR_LEN) ;
  234.     else
  235.         memcpy(cp, ip_hdr, HDR_LEN) ;
  236.     cp += HDR_LEN ;
  237.  
  238.     /* Copy input to output, escaping special characters */
  239.     while(pullup(&bp,&c,1) == 1){
  240.         switch(c & 0xff){
  241.         case SLFP_ESC:
  242.             *cp++ = SLFP_ESC;
  243.             *cp++ = SLFP_ESC - SLFP_ESC;
  244.             break;
  245.         case SLFP_END:
  246.             *cp++ = SLFP_ESC;
  247.             *cp++ = SLFP_END - SLFP_ESC;
  248.             break;
  249.         case SLFP_ACK:
  250.             *cp++ = SLFP_ESC;
  251.             *cp++ = SLFP_ACK - SLFP_ESC;
  252.             break;
  253.         case SLFP_REQ:
  254.             *cp++ = SLFP_ESC;
  255.             *cp++ = SLFP_REQ - SLFP_ESC;
  256.             break;
  257.         default:
  258.             *cp++ = c;
  259.         }
  260.     }
  261.     *cp++ = SLFP_END;
  262.     lbp->cnt = cp - lbp->data;
  263.     return lbp;
  264. }
  265.  
  266. #ifdef    MSDOS
  267. /* Invoked when SLFP_REQ is received during xmit of outgoing packet.
  268.  * This allows immediate reception of packet from SCP, rather than
  269.  * forcing it to buffer it until we finish sending the outgoing packet
  270.  */
  271. static
  272. unsigned
  273. slfp_urgent(dev)
  274. int16 dev;    /* SL/FP unit number */
  275. {
  276.     register struct dma *dp ;
  277.  
  278.     dp = &asy[dev].dma ;
  279.     if (dp->last_octet == SLFP_ESC)
  280.     return 256 ;
  281.     else {
  282.     asy[dev].urgent = NULLCHAR ;
  283.     return SLFP_ACK ;
  284.     }
  285. }
  286. #endif
  287.  
  288. void
  289. hndl_rcvd_req(dev, sp)
  290. int16 dev;    /* SL/FP unit number */
  291. register struct slfp *sp;
  292. {
  293.     char i_state ;
  294.  
  295.     if (sp->reqd) { /* REQ before rcv'g END of last Packet! */
  296.     sp->missed_ends++ ;
  297.     free_p(sp->rbp);    /* throw away current packet */
  298.     sp->rbp = NULLBUF;
  299.     sp->rcnt = 0;
  300.     }
  301.  
  302.     sp->reqd = 1 ;
  303.     i_state = disable() ;
  304. #ifdef    MSDOS
  305.     if (asy[dev].dma.flags)
  306.     asy[dev].urgent = slfp_urgent ;
  307.     else
  308. #endif
  309.     asy_output(dev, slfp_ack, ACK_LEN) ;
  310.     restore(i_state) ;
  311. }
  312.  
  313. void
  314. hndl_rcvd_ack(dev, sp)
  315. int16 dev;    /* SL/FP unit number */
  316. register struct slfp *sp;
  317. {
  318.     char i_state ;
  319.  
  320.     i_state = disable() ;
  321.     if (sp->req_pending == 0) {
  322.         sp->false_acks++ ;
  323.         restore(i_state) ;
  324.         return ;
  325.     }
  326.     sp->req_pending = 0 ;
  327.     stop_timer(&(sp->req_timer)) ;
  328.     restore(i_state) ;
  329.     sp->tbp = dequeue(&sp->sndq);
  330.     sp->sndcnt--;
  331.     asy_output(dev,sp->tbp->data,sp->tbp->cnt);
  332. }
  333.  
  334. /* Process incoming bytes in SL/FP format
  335.  * When a buffer is complete, return it; otherwise NULLBUF
  336.  */
  337. static
  338. struct mbuf *
  339. slfp_decode(dev,c)
  340. int16 dev;    /* SL/FP unit number */
  341. char c;        /* Incoming character */
  342. {
  343.     struct mbuf *bp;
  344.     register struct slfp *sp;
  345.     unsigned char uc ;
  346.  
  347.     sp = &slfp[dev];
  348.  
  349.     uc = c & 0xff;
  350.     if (uc == SLFP_REQ) {
  351.         hndl_rcvd_req(dev, sp) ;
  352.         return NULLBUF ;
  353.     }
  354.     if (uc == SLFP_ACK) {
  355.         hndl_rcvd_ack(dev, sp) ;
  356.         return NULLBUF ;
  357.     }
  358.     if (sp->reqd == 0) {
  359.         return NULLBUF ;
  360.     }
  361.  
  362.     switch(uc){
  363.     case SLFP_END:
  364.         sp->reqd = 0 ;
  365.         /* Kick upstairs */
  366.         bp = sp->rbp;
  367.         sp->rbp = NULLBUF;
  368.         sp->rcnt = 0;
  369.         return bp;
  370.         break ;
  371.  
  372.     case SLFP_ESC:
  373.         sp->escaped = 1;
  374.         return NULLBUF;
  375.     }
  376.     if(sp->escaped){
  377.         sp->escaped = 0;
  378.         uc += SLFP_ESC;
  379.         switch(uc){
  380.         case SLFP_ESC:
  381.         case SLFP_REQ:
  382.         case SLFP_ACK:
  383.         case SLFP_END:
  384.             break;
  385.         default:
  386.             uc -= SLFP_ESC;
  387.             sp->bad_esc++;
  388.             sp->errors++;
  389.         }
  390.     }
  391.     /* We reach here with a character for the buffer;
  392.      * make sure there's space for it
  393.      */
  394.     if(sp->rbp == NULLBUF){
  395.         /* Allocate first mbuf for new packet */
  396.         if((sp->rbp1 = sp->rbp = alloc_mbuf(SLFP_ALLOC)) == NULLBUF)
  397.             return NULLBUF; /* No memory, drop */
  398.         sp->rcp = sp->rbp->data;
  399.     } else if(sp->rbp1->cnt == SLFP_ALLOC){
  400.         /* Current mbuf is full; link in another */
  401.         if((sp->rbp1->next = alloc_mbuf(SLFP_ALLOC)) == NULLBUF){
  402.             /* No memory, drop whole thing */
  403.             free_p(sp->rbp);
  404.             sp->rbp = NULLBUF;
  405.             sp->rcnt = 0;
  406.             return NULLBUF;
  407.         }
  408.         sp->rbp1 = sp->rbp1->next;
  409.         sp->rcp = sp->rbp1->data;
  410.     }
  411.     /* Store the character, increment fragment and total
  412.      * byte counts
  413.      */
  414.     *sp->rcp++ = uc;
  415.     sp->rbp1->cnt++;
  416.     sp->rcnt++;
  417.     return NULLBUF;
  418. }
  419. /* Process SL/FP line I/O */
  420. int
  421. doslfp(interface)
  422. struct interface *interface;
  423. {
  424.     char c;
  425.     struct mbuf *bp;
  426.     int16 dev;
  427.     int16 asy_recv();
  428.  
  429.     dev = interface->dev;
  430.     /* Process any pending input */
  431.     while(asy_recv(dev,&c,1) != 0)
  432.         if((bp = slfp_decode(dev,c)) != NULLBUF) {
  433.             (*slfp[dev].recv)(interface,bp);
  434.         }
  435.  
  436.     /* Kick the transmitter if it's idle */
  437.     if(stxrdy(dev))
  438.         slfp_asy_start(dev);
  439. }
  440.  
  441. /* Handle Address Reply packets
  442.  */
  443. void
  444. addr_reply(dev,bp)
  445. int16 dev;
  446. struct mbuf *bp;
  447. {
  448.     if (len_mbuf(bp) != 4) { /* Invalid Address Response */
  449.     free_p(bp) ;
  450.     return ;
  451.     }
  452.     if (!slfp[dev].ar_pending) {
  453.     free_p(bp) ;
  454.     return ;
  455.     }
  456.     stop_timer(&slfp[dev].ar_timer) ;
  457.     slfp[dev].ar_pending = 0 ;
  458.     ip_addr = (unsigned char)(*bp->data++) ;
  459.     ip_addr <<= 8 ;
  460.     ip_addr |= (unsigned char)(*bp->data++) ;
  461.     ip_addr <<= 8 ;
  462.     ip_addr |= (unsigned char)(*bp->data++) ;
  463.     ip_addr <<= 8 ;
  464.     ip_addr |= (unsigned char)(*bp->data++) ;
  465.     free_p(bp) ;
  466. }
  467.  
  468. /* Unwrap incoming SL/FP packets -- use link level header to determine
  469.  * howto handle packet
  470.  */
  471. slfp_recv(interface,bp)
  472. struct interface *interface;
  473. struct mbuf *bp;
  474. {
  475.     void ip_route();
  476.  
  477.     dump(interface,IF_TRACE_IN,TRACE_SLFP,bp);
  478.     if (len_mbuf(bp) < HDR_LEN) {
  479.         free_p(bp) ;
  480.         return ;
  481.     }
  482.     if (memcmp(ip_hdr, bp->data, HDR_LEN) == 0) {
  483.         bp->data += HDR_LEN ;
  484.         bp->cnt -= HDR_LEN ;
  485.         dump(interface,IF_TRACE_IN,TRACE_IP,bp);
  486.         ip_route(bp,0); /* By def'n, all inbound packets are addr'd to us */
  487.     }
  488.     else if (memcmp(ar_hdr, bp->data, HDR_LEN) == 0) {
  489.         bp->data += HDR_LEN ;
  490.         bp->cnt -= HDR_LEN ;
  491.         dump(interface,IF_TRACE_IN,TRACE_IP,bp);
  492.         addr_reply(interface->dev,bp);
  493.     } else {
  494.         dump(interface,IF_TRACE_IN,TRACE_IP,bp);
  495.         free_p(bp) ;
  496.     }
  497. }
  498.  
  499. int
  500. slfp_dump(bpp, check)
  501. struct mbuf **bpp;
  502. int check ;
  503. {
  504.     if(bpp == NULLBUFP || *bpp == NULLBUF)
  505.         return 0;    
  506.  
  507.     printf("SLFP: ");
  508.     /* Sneak peek at IP header and find length */
  509.     if (len_mbuf(*bpp) < HDR_LEN) {
  510.         printf("packet too short!\n");
  511.         return 0;
  512.     }
  513.  
  514.     if (memcmp(ip_hdr, (*bpp)->data, HDR_LEN) == 0)
  515.         printf("IP Packet\n") ;
  516.     else if (memcmp(ar_hdr, (*bpp)->data, HDR_LEN) == 0)
  517.         printf("Addr Req Packet\n") ;
  518.     else
  519.         printf("bad header\n") ;
  520.  
  521.     return 0 ;
  522. }
  523.